<?php

namespace App\Http\Controllers\WebApp\Api;

use App\Exceptions\ApiException;
use App\Http\Controllers\Traits\PassportProxyTrait;
use App\Http\Requests\UserPost;
use App\Rules\MobileRule;
use App\Tables\User;
use App\Tables\UserScoreTransferRecord;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Validator;
use App\Jobs\SendMobileSms;
use Throwable;
use Exception;
use DB;
use MobileSms;

class UserController extends BaseController
{

    use PassportProxyTrait;

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @param UserPost $request
     * @return \Illuminate\Http\Response
     * @throws ApiException
     */
    public function create(UserPost $request)
    {
        $data = $request->all([
            'name', 'email', 'mobile', 'auth_code', 'invite_code', 'baidu_push_channel_id',
            'password', 'province_code', 'city_code', 'source', 'district_code', 'wx_official_open_id', 'wx_union_id'
        ]);

        /**
         * 校验验证码
         */
        $result = MobileSms::verifyAuthCode($request->mobile, $request->auth_code, config('auth.register.auth_code.ttl'));
        if ($result !== true) {
            throw new ApiException($result);
        }

        /**
         * 验证邀请码是否存在
         * 如果用户填写了邀请码则进行验证，不填写则不验证
         */
        if ($request->filled('invite_code')) {
            $inviter = User::general()->where('mobile', base_convert($request->invite_code, 32, 10))->first();
            if (empty($inviter)) {
                throw new ApiException('邀请码不存在');
            }
        }

        $user = User::create([
            'type' => 0,
            'name' => $data['mobile'],
            'mobile' => $data['mobile'],
            'baidu_push_channel_id' => $data['baidu_push_channel_id'],
            'province_code' => $data['province_code'],
            'city_code' => $data['city_code'],
            'district_code' => $data['district_code'],
            'invite_code' => $data['invite_code'],
            'wx_official_open_id' => $data['wx_official_open_id'],
            'wx_union_id' => $data['wx_union_id'],
            'password' => bcrypt($data['password']),
            'source' => strtolower($data['source']) ?: 'web'
        ]);

        if (empty($user)) {
            throw new ApiException('用户注册失败');
        }

        return response()->json(ajax_return(true, '用户注册成功'));
    }

    /**
     * 用户登录获取Token
     * @return mixed
     */
    public function login()
    {
        return $this->oAuthToken();
    }

    /**
     * 获取手机验证码
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws ApiException
     */
    public function authCode(Request $request)
    {
        Validator::make($request->all(), [
            'mobile' => new MobileRule()
        ], [], ['mobile' => '手机号'])->validate();

        $sms_code = random_int(100000, 999999);
        $sms_content = "验证码为【{$sms_code}】您正在进行注册业务，请将验证码输入，如非本人操作请勿泄露。【加电侠】";
        $sms = MobileSms::makeAuthCode($request->mobile, $sms_code, $sms_content, 'register');

        if (empty($sms)) {
            throw new ApiException('发送验证码失败');
        }

        dispatch(new SendMobileSms($sms));

        return response()->json(ajax_return(true, '验证码已发送'));
    }

    /**
     * 获取重置密码的手机验证码
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws ApiException
     */
    public function authCodeForResetPassword(Request $request)
    {
        Validator::make($request->all(), [
            'mobile' => new MobileRule()
        ], [], ['mobile' => '手机号'])->validate();


        $user = User::where('mobile', $request->mobile)->where('type', 0)->first();
        if (empty($user)) {
            throw new ApiException('用户不存在');
        }

        $sms_code = random_int(100000, 999999);
        $sms_content = "验证码为【{$sms_code}】您正在进行重置密码业务，请将验证码输入，如非本人操作请勿泄露。【加电侠】";
        $sms = MobileSms::makeAuthCode($request->mobile, $sms_code, $sms_content, 'password_reset');

        if (empty($sms)) {
            throw new ApiException('发送验证码失败');
        }

        dispatch(new SendMobileSms($sms));

        return response()->json(ajax_return(true, '验证码已发送'));
    }

    /**
     * 短信重置密码
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws ApiException
     */
    public function resetPasswordForMobile(Request $request)
    {
        Validator::make($request->all(), [
            'mobile' => new MobileRule(),
            'auth_code' => 'required',
            'password' => "required|string|max:18|min:6",
            're_password' => 'same:password',
        ], [], ['mobile' => '手机号', 'auth_code' => '验证码', 'password' => '密码', 're_password' => '确认密码'])->validate();


        /**
         * 校验验证码
         */
        $result = MobileSms::verifyAuthCode($request->mobile, $request->auth_code, config('auth.register.auth_code.ttl'));
        if ($result !== true) {
            throw new ApiException($result);
        }

        $user = User::where('mobile', $request->mobile)->where('type', 0)->first();

        if (empty($user)) {
            throw new ApiException('用户不存在');
        }

        $user->password = bcrypt($request->password);
        $res = $user->save();

        if ($res === false) {
            throw new ApiException('重置密码失败');
        }

        return response()->json(ajax_return(true, '密码重置成功'));
    }

    /**
     * 签到赠送积分
     * @return \Illuminate\Http\JsonResponse
     * @throws ApiException
     */
    public function signInGiveScore()
    {
        $score = config('system.sign_in.give_score_num', 0);
        if ($score <= 0 || config('system.sign_in.status', false) !== true) {
            throw new ApiException('签到送积分活动尚未开启，敬请期待');
        }

        /**
         * 判断今日是否已经签到过了
         */
        if ($this->user->is_signed_in) {
            throw new ApiException('今天已经签到了');
        }

        DB::beginTransaction();
        try {
            $user = User::where('id', $this->user->id)->lockForUpdate()->first();
            if (empty($user)) {
                throw new Exception('用户不存在');
            }
            // 签到后的总积分
            $total_score = $user->score + $score;
            $user->score = $total_score;
            if ($user->save() === false) {
                throw new Exception('更新用户积分账户失败');
            }

            $score_record = UserScoreTransferRecord::create([
                'user_id' => $this->user->id,
                'type' => 'sign_in_give',
                'order_sn' => 'SIGNIN' . $this->user->id . date('Ymd'),
                'score' => $score,
                'total_score' => $total_score
            ]);

            if (empty($score_record)) {
                throw new Exception('增加用户积分记录数据失败');
            }

            // 清除缓存
            $cacheKey = 'user_sign_in_' . $user->id . '_' . date('Ymd');
            Cache::tags('user_sign_in')->forget($cacheKey);

            DB::commit();
            return response()->json(ajax_return(true, '签到成功', ['score' => $score]));
        } catch (QueryException $e) {
            DB::rollBack();
        } catch (Exception $e) {
            DB::rollBack();
        } catch (Throwable $e) {
            DB::rollBack();
        }

        return response()->json(ajax_return(false, '签到失败', ['score' => 0]));
    }

    /**
     * 获取积分记录列表数据
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function scores(Request $request)
    {
        $query = new UserScoreTransferRecord();
        $query = $query->where('user_id', $this->user->id);
        /**
         * 设置查询条件
         */

        if ($request->filled('keyword')) {
            $query = $query->where(function($query) use ($request) {
                $query->orWhere('order_sn', 'like', "%{$request->keyword}%");
            });
        }

        /**
         * 排序
         */
        $query = $query->orderBy('created_at', 'desc');

        /**
         * 分页
         */
        $page = $request->get('page', 1);
        $pageSize = $request->header('pageSize') ?: $request->get('pageSize', 20);

        $skip = $pageSize * ($page - 1);
        $data = $query->skip($skip)->take($pageSize)->get();

        $data = $data->toArray();

        return response()->json(ajax_return(true, 'ok', $data));
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param UserPost|Request $request
     * @return \Illuminate\Http\Response
     * @throws ApiException
     * @internal param $user_id
     * @internal param int $id
     */
    public function update(UserPost $request)
    {
        $data = $request->all(['email', 'password', 'baidu_push_channel_id', 'province_code', 'city_code', 'district_code']);

        $data = array_filter($data);

        $user = User::where('id', $this->user->id)->first();

        if (empty($user)) {
            throw new ApiException('用户不存在');
        }

        if ($request->filled('password')) {
            $data['password'] = bcrypt($data['password']);
        }

        if (!$user->update($data)) {
            throw new ApiException('用户信息更新失败');
        }

        return response()->json(ajax_return(true, '用户信息更新成功'));
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}
